package com.office.system.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ObjectUtil;
import com.office.common.constant.CacheNames;
import com.office.common.core.domain.PageQuery;
import com.office.common.core.page.TableDataInfo;
import com.office.common.core.service.OssService;
import com.office.common.exception.ServiceException;
import com.office.common.utils.BeanCopyUtils;
import com.office.common.utils.JsonUtils;
import com.office.common.utils.StringUtils;
import com.office.common.utils.file.FileUtils;
import com.office.common.utils.redis.CacheUtils;
import com.office.common.utils.redis.RedisUtils;
import com.office.common.utils.spring.SpringUtils;
import com.office.oss.constant.OssConstant;
import com.office.oss.core.OssClient;
import com.office.oss.entity.UploadResult;
import com.office.oss.enumd.AccessPolicyType;
import com.office.oss.factory.OssFactory;
import com.office.system.domain.SysOss;
import com.office.system.domain.SysOssConfig;
import com.office.system.domain.bo.SysOssBo;
import com.office.system.domain.vo.SysOssVo;
import com.office.system.mapper.SysOssConfigMapper;
import com.office.system.mapper.SysOssMapper;
import com.office.system.service.ISysOssService;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import jakarta.annotation.PostConstruct;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.Calendar;

/**
 * 文件上传 服务层实现
 *
 * @author 数字牧马人
 */
@RequiredArgsConstructor
@Service
public class SysOssServiceImpl implements ISysOssService, OssService {

    private final SysOssMapper baseMapper;
    private final SysOssConfigMapper ossConfigMapper;

    @Override
    public TableDataInfo<SysOssVo> queryPageList(SysOssBo bo, PageQuery pageQuery) {
        SysOss sysOss = new SysOss();
        if (bo != null) {
            BeanCopyUtils.copy(bo, sysOss);
        }
        List<SysOss> list = baseMapper.selectSysOssList(sysOss);
        if (list == null) {
            list = new ArrayList<>();
        }
        List<SysOssVo> voList = list.stream()
            .map(item -> {
                SysOssVo vo = new SysOssVo();
                BeanCopyUtils.copy(item, vo);
                return matchingUrl(vo);
            })
            .collect(Collectors.toList());

        // 计算总数
        long total = voList.size();

        // 如果没有分页参数，返回所有数据
        if (pageQuery == null) {
            return TableDataInfo.build(voList, total);
        }

        // 确保分页参数有效
        int pageNum = pageQuery.getPageNum() == null ? 1 : pageQuery.getPageNum();
        int pageSize = pageQuery.getPageSize() == null ? 10 : pageQuery.getPageSize();

        // 手动分页
        int fromIndex = (pageNum - 1) * pageSize;
        int toIndex = Math.min(fromIndex + pageSize, voList.size());
        List<SysOssVo> pageList = fromIndex < voList.size() ? voList.subList(fromIndex, toIndex) : new ArrayList<>();
        return TableDataInfo.build(pageList, total);
    }

    @Override
    public List<SysOssVo> listByIds(Collection<Long> ossIds) {
        List<SysOssVo> list = new ArrayList<>();
        for (Long id : ossIds) {
            SysOssVo vo = SpringUtils.getAopProxy(this).getById(id);
            if (ObjectUtil.isNotNull(vo)) {
                list.add(this.matchingUrl(vo));
            }
        }
        return list;
    }

    @Override
    public String selectUrlByIds(String ossIds) {
        List<String> list = new ArrayList<>();
        for (Long id : StringUtils.splitTo(ossIds, Convert::toLong)) {
            SysOssVo vo = SpringUtils.getAopProxy(this).getById(id);
            if (ObjectUtil.isNotNull(vo)) {
                list.add(this.matchingUrl(vo).getUrl());
            }
        }
        return String.join(",", list);
    }

    @Cacheable(cacheNames = CacheNames.SYS_OSS, key = "#ossId")
    @Override
    public SysOssVo getById(Long ossId) {
        SysOss sysOss = baseMapper.selectSysOssById(ossId);
        if (sysOss != null) {
            SysOssVo vo = new SysOssVo();
            BeanCopyUtils.copy(sysOss, vo);
            return vo;
        }
        return null;
    }

    @Override
    public void download(Long ossId, HttpServletResponse response) throws IOException {
        SysOssVo sysOss = SpringUtils.getAopProxy(this).getById(ossId);
        if (ObjectUtil.isNull(sysOss)) {
            throw new ServiceException("文件数据不存在!");
        }
        FileUtils.setAttachmentResponseHeader(response, sysOss.getOriginalName());
        response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8");
        OssClient storage = OssFactory.instance();
        try(InputStream inputStream = storage.getObjectContent(sysOss.getUrl())) {
            int available = inputStream.available();
            IoUtil.copy(inputStream, response.getOutputStream(), available);
            response.setContentLength(available);
        } catch (Exception e) {
            throw new ServiceException(e.getMessage());
        }
    }

    @Override
    public SysOssVo upload(MultipartFile file) {
        String originalfileName = file.getOriginalFilename();
        String suffix = StringUtils.substring(originalfileName, originalfileName.lastIndexOf("."), originalfileName.length());
        OssClient storage = OssFactory.instance();
        UploadResult uploadResult;
        try {
            uploadResult = storage.uploadSuffix(file.getBytes(), suffix, file.getContentType());
        } catch (IOException e) {
            throw new ServiceException(e.getMessage());
        }
        // 保存文件信息
        SysOss oss = new SysOss();
        oss.setUrl(uploadResult.getUrl());
        oss.setFileSuffix(suffix);
        oss.setFileName(uploadResult.getFilename());
        oss.setOriginalName(originalfileName);
        oss.setService(storage.getConfigKey());
        oss.setFileSize(file.getSize());
        baseMapper.insertSysOss(oss);
        SysOssVo sysOssVo = new SysOssVo();
        BeanCopyUtils.copy(oss, sysOssVo);
        return this.matchingUrl(sysOssVo);
    }

    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            // 做一些业务上的校验,判断是否需要校验
        }
        for (Long id : ids) {
            SysOss sysOss = baseMapper.selectSysOssById(id);
            if (sysOss != null) {
                OssClient storage = OssFactory.instance(sysOss.getService());
                storage.delete(sysOss.getUrl());
                baseMapper.deleteSysOssById(id);
            }
        }
        return true;
    }

    @Override
    public Map<String, Object> getDocumentStats() {
        Map<String, Object> stats = new HashMap<>();
        List<SysOss> allFiles = baseMapper.selectSysOssList(new SysOss());
        stats.put("totalDocuments", allFiles.size());

        // 获取当前时间
        Calendar now = Calendar.getInstance();

        // 今日
        int todayCount = 0;
        // 本周
        int weekCount = 0;
        // 本月
        int monthCount = 0;

        for (SysOss file : allFiles) {
            Date createTime = file.getCreateTime();
            Calendar fileCal = Calendar.getInstance();
            fileCal.setTime(createTime);

            // 今日
            boolean isToday = now.get(Calendar.YEAR) == fileCal.get(Calendar.YEAR)
                    && now.get(Calendar.DAY_OF_YEAR) == fileCal.get(Calendar.DAY_OF_YEAR);
            if (isToday) todayCount++;

            // 本周
            boolean isSameWeek = now.get(Calendar.YEAR) == fileCal.get(Calendar.YEAR)
                    && now.get(Calendar.WEEK_OF_YEAR) == fileCal.get(Calendar.WEEK_OF_YEAR);
            if (isSameWeek) weekCount++;

            // 本月
            boolean isSameMonth = now.get(Calendar.YEAR) == fileCal.get(Calendar.YEAR)
                    && now.get(Calendar.MONTH) == fileCal.get(Calendar.MONTH);
            if (isSameMonth) monthCount++;
        }

        stats.put("todayUploads", todayCount);
        stats.put("weekUploads", weekCount);
        stats.put("monthUploads", monthCount);

        return stats;
    }

    /**
     * 匹配Url
     *
     * @param oss OSS对象
     * @return oss 匹配Url的OSS对象
     */
    private SysOssVo matchingUrl(SysOssVo oss) {
        if (oss == null || StringUtils.isEmpty(oss.getService())) {
            return oss;
        }
        OssClient storage = OssFactory.instance(oss.getService());
        // 仅修改桶类型为 private 的URL，临时URL时长为120s
        if (AccessPolicyType.PRIVATE == storage.getAccessPolicy()) {
            oss.setUrl(storage.getPrivateUrl(oss.getFileName(), 120));
        }
        return oss;
    }

    @PostConstruct
    public void init() {
        List<SysOssConfig> list = ossConfigMapper.selectSysOssConfigList(new SysOssConfig());
        // 加载OSS初始化配置
        for (SysOssConfig config : list) {
            String configKey = config.getConfigKey();
            if ("0".equals(config.getStatus())) {
                RedisUtils.setCacheObject(OssConstant.DEFAULT_CONFIG_KEY, configKey);
            }
            CacheUtils.put(CacheNames.SYS_OSS_CONFIG, config.getConfigKey(), JsonUtils.toJsonString(config));
        }
    }
}
